import React, {memo} from 'react';
import type {CustomRendererProps, TBlock} from 'react-native-render-html';
import {AttachmentContext} from '@components/AttachmentContext';
import {getButtonRole} from '@components/Button/utils';
import {isDeletedNode} from '@components/HTMLEngineProvider/htmlEngineUtils';
import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus';
import {ShowContextMenuContext, showContextMenuForReport} from '@components/ShowContextMenuContext';
import ThumbnailImage from '@components/ThumbnailImage';
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import {getFileName, getFileType, splitExtensionFromFileName} from '@libs/fileDownload/FileUtils';
import Navigation from '@libs/Navigation/Navigation';
import {isArchivedNonExpenseReport} from '@libs/ReportUtils';
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';

function ImageRenderer({tnode}: CustomRendererProps<TBlock>) {
    const icons = useMemoizedLazyExpensifyIcons(['Document', 'GalleryNotFound'] as const);
    const styles = useThemeStyles();
    const {translate} = useLocalize();

    // Re-render this component when account.shouldUseStagingServer changes
    useOnyx(ONYXKEYS.SHOULD_USE_STAGING_SERVER, {canBeMissing: true});

    const htmlAttribs = tnode.attributes;
    const isDeleted = isDeletedNode(tnode);

    // There are two kinds of images that need to be displayed:
    //
    //     - Chat Attachment images
    //
    //           Images uploaded by the user account via the app or email.
    //           These have a full-sized image `htmlAttribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE]`
    //           and a thumbnail `htmlAttribs.src`. Both of these URLs need to have
    //           an authToken added to them in order to control who
    //           can see the images.
    //
    //     - Non-Attachment Images
    //
    //           These could be hosted from anywhere (Expensify or another source)
    //           and are not protected by any kind of access control e.g. certain
    //           Concierge responder attachments are uploaded to S3 without any access
    //           control and thus require no authToken to verify access.
    //
    const attachmentSourceAttribute =
        htmlAttribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE] ?? (new RegExp(CONST.ATTACHMENT_OR_RECEIPT_LOCAL_URL, 'i').test(htmlAttribs.src) ? htmlAttribs.src : null);
    const isAttachmentOrReceipt = !!attachmentSourceAttribute;
    const attachmentID = htmlAttribs[CONST.ATTACHMENT_ID_ATTRIBUTE];

    // Files created/uploaded/hosted by App should resolve from API ROOT. Other URLs aren't modified
    const previewSource = tryResolveUrlFromApiRoot(htmlAttribs.src);
    // The backend always returns these thumbnails with a .jpg extension, even for .png images.
    // As a workaround, we remove the .1024.jpg or .320.jpg suffix only for .png images,
    // For other image formats, we retain the thumbnail as is to avoid unnecessary modifications.
    const processedPreviewSource = typeof previewSource === 'string' ? previewSource.replaceAll(/\.png\.(1024|320)\.jpg$/g, '.png') : previewSource;
    const source = tryResolveUrlFromApiRoot(isAttachmentOrReceipt ? attachmentSourceAttribute : htmlAttribs.src);

    const alt = htmlAttribs.alt;
    const imageWidth = (htmlAttribs['data-expensify-width'] && parseInt(htmlAttribs['data-expensify-width'], 10)) || undefined;
    const imageHeight = (htmlAttribs['data-expensify-height'] && parseInt(htmlAttribs['data-expensify-height'], 10)) || undefined;
    const imagePreviewModalDisabled = htmlAttribs['data-expensify-preview-modal-disabled'] === 'true';

    const fileType = getFileType(attachmentSourceAttribute);
    const fallbackIcon = fileType === CONST.ATTACHMENT_FILE_TYPE.FILE ? icons.Document : icons.GalleryNotFound;
    const theme = useTheme();

    let fileName = htmlAttribs[CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE] || getFileName(`${isAttachmentOrReceipt ? attachmentSourceAttribute : htmlAttribs.src}`);
    const fileInfo = splitExtensionFromFileName(fileName);
    if (!fileInfo.fileExtension) {
        fileName = `${fileInfo?.fileName || CONST.DEFAULT_IMAGE_FILE_NAME}.jpg`;
    }

    const thumbnailImageComponent = (
        <ThumbnailImage
            previewSourceURL={processedPreviewSource}
            style={styles.webViewStyles.tagStyles.img}
            isAuthTokenRequired={isAttachmentOrReceipt}
            fallbackIcon={fallbackIcon}
            imageWidth={imageWidth}
            imageHeight={imageHeight}
            isDeleted={isDeleted}
            altText={alt}
            fallbackIconBackground={theme.highlightBG}
            fallbackIconColor={theme.border}
        />
    );

    return imagePreviewModalDisabled ? (
        thumbnailImageComponent
    ) : (
        <ShowContextMenuContext.Consumer>
            {({onShowContextMenu, anchor, report, isReportArchived, action, checkIfContextMenuActive, isDisabled, shouldDisplayContextMenu}) => (
                <AttachmentContext.Consumer>
                    {({reportID, accountID, type}) => (
                        <PressableWithoutFocus
                            style={[styles.noOutline]}
                            onPress={() => {
                                if (!source || !type) {
                                    return;
                                }

                                const attachmentLink = tnode.parent?.attributes?.href;
                                const route = ROUTES.REPORT_ATTACHMENTS?.getRoute({
                                    attachmentID,
                                    reportID,
                                    type,
                                    source,
                                    accountID,
                                    isAuthTokenRequired: isAttachmentOrReceipt,
                                    originalFileName: fileName,
                                    attachmentLink,
                                });
                                Navigation.navigate(route);
                            }}
                            onLongPress={(event) => {
                                if (isDisabled || !shouldDisplayContextMenu) {
                                    return;
                                }
                                return onShowContextMenu(() =>
                                    showContextMenuForReport(event, anchor, report?.reportID, action, checkIfContextMenuActive, isArchivedNonExpenseReport(report, isReportArchived)),
                                );
                            }}
                            isNested
                            shouldUseHapticsOnLongPress
                            role={getButtonRole(true)}
                            accessibilityLabel={translate('accessibilityHints.viewAttachment')}
                        >
                            {thumbnailImageComponent}
                        </PressableWithoutFocus>
                    )}
                </AttachmentContext.Consumer>
            )}
        </ShowContextMenuContext.Consumer>
    );
}

ImageRenderer.displayName = 'ImageRenderer';

export default memo(ImageRenderer, (prevProps, nextProps) => prevProps.tnode.attributes === nextProps.tnode.attributes);
